/*
 * Implementation of getcurrenttime system call.
 *
 * Ben Marks, Chris Lekas - CS 45, February 2014
 *
 */
#include <linux/kernel.h>   // can only be included at kernel-level
#include <asm/uaccess.h>    
#include <linux/syscalls.h> 
#include <linux/time.h>
#include <linux/errno.h>

/* getcurrenttime - Fills in the struct timespec passed in by reference with
 *  the current kernel time.  Prints the time at the kernel level if flag is
 *  non-zero.
 *
 * @param flag - If non-zero, time printed to kernel log.
 * @param tval - struct timespec in user-space to fill in.
 * @return 0 on success. On failure, sets errno and returns -1.
 */
SYSCALL_DEFINE2(getcurrenttime, int, flag, struct timespec __user *, tval) {
  
  if (access_ok(VERIFY_WRITE, tval, sizeof(struct timespec))) {
    // Pointer address might be valid.
    struct timespec kerVal;
    if (!copy_from_user(&kerVal, tval, sizeof(struct timespec))) {
      // Able to copy over struct from user-space.
      // Get time and set struct.
      struct timespec curr = current_kernel_time();
      kerVal.tv_sec = curr.tv_sec;
      kerVal.tv_nsec = curr.tv_nsec;
      if (flag) { // Print as needed.
	printk("The Current Time Is: %d secs and %d nsecs.\n",
                kerVal.tv_sec, kerVal.tv_nsec );
      }
      if (!copy_to_user(tval, &kerVal, sizeof(struct timespec))) {
	// Able to copy back to user-space.
	return 0;
      }
      else { // Can't copy back to user-space.
	return -EFAULT;
      }
    }
    else { // Can't copy from user-space.
      return -EFAULT;
    }
  }
  else { // Pointer address is invalid.
    return -EFAULT;
  }

  return -1; // Never reach here.
}
